package com.yzy.fly.bean;

import com.google.common.collect.Lists;
import com.yzy.fly.environment.BeanDefinitionInfo;
import com.yzy.fly.function.httpClient.FlyBeanDefinitionRegistry;
import com.yzy.fly.function.httpClient.FlyHttpClientBeanDefinitionRegistry;
import com.yzy.fly.function.logging.Log;
import com.yzy.fly.function.logging.LogFactory;
import com.yzy.fly.function.webServiceClient.FlyWebServiceClientBeanDefinitionRegistry;
import com.yzy.fly.kernel.model.ability.role.RoleRedisTemplateBeanDefinitionRegistry;
import lombok.Getter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.ResolvableType;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class FlyCustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {

    private static Log log = LogFactory.getLog(FlyCustomBeanDefinitionRegistryPostProcessor.class);

    @Autowired(required = false)
    private List<FlyBeanDefinitionRegistry> flyBeanDefinitionRegistries;

    @Getter
    private List<BeanDefinitionInfo> beanDefinitionInfoList = Lists.newArrayList();

    private static ApplicationContext applicationContext;

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {

//        System.out.println("flyBeanDefinitionRegistries:"+flyBeanDefinitionRegistries.size());

//        Map<String, FlyBeanDefinitionRegistry> beansOfType = this.applicationContext.getBeansOfType(FlyBeanDefinitionRegistry.class);
//        System.out.println("flyBeanDefinitionRegistries:"+beansOfType.size());
        new RoleRedisTemplateBeanDefinitionRegistry().run(beanDefinitionRegistry);
        new FlyHttpClientBeanDefinitionRegistry().run(beanDefinitionRegistry);
        new FlyWebServiceClientBeanDefinitionRegistry().run(beanDefinitionRegistry);
//        new FlyMapperBeanDefinitionRegistry().run(beanDefinitionRegistry);
//        FlyProperties flyProperties = applicationContext.getBean(FlyProperties.class);
//        System.out.println(flyProperties);
        // 手动注册的Bean类型 ， 由于我要注册的其实是 接口的实现类
        // 所以采用FactoryBean方式创建Bean
        // 若仅仅需要对Bean注入值，可以直接指定想创建的Bean的class
//        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(RoleRedisTemplateBeanFactory.class); //这里可以直接改成TestFactory.class
//        AbstractBeanDefinition definition = builder.getRawBeanDefinition();

        //亦可通过setBeanClass方式指定创建的类
        //definition.setBeanClass(TestFactory.class);
        //项目和jar里的role全部加载生产redisTemplate
//        Set<Class<? extends Role>> classes = null;
//        try {
//            classes = ReflectionsUtil.getSubTypesOf(Role.class);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }

        int beanDefinitionCount = beanDefinitionRegistry.getBeanDefinitionCount();
        String[] beanDefinitionNames = beanDefinitionRegistry.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = beanDefinitionRegistry.getBeanDefinition(beanDefinitionName);
//            log.info(beanDefinitionName);
            addBeanDefinitionInfo(beanDefinitionName,beanDefinition);
        }

//        AppApp.class.getName() + RedisTemplate.class.getName()
//        RedisTemplate<String,AppApp> bean = (RedisTemplate<String,AppApp>)applicationContext.getBean("com.yzy.fly.kernel.model.AppApporg.springframework.data.redis.core.RedisTemplate");
//
//        System.out.println(bean);
//        Map<String, MetadataModel> cacheMap = metadataModelCache.getCacheMap();
//
//        for (String key : cacheMap.keySet()) {
//            System.out.println(key);
//        }

        //由于TestBean同时有两个不同名的Bean实例，需要手动指定注入
//        TestBean c = applicationContext.getBean("testBean", TestBean.class);
//        definition.getPropertyValues().addPropertyValue("testBean",c); //set 方式autowired，需要指定属性有set方法

        // 构造方法autowired，FactoryBean 的 construct 方法必须有 ， 两种注入方式选其一
        // definition.getConstructorArgumentValues().addGenericArgumentValue();

        // 对 TestFactory 中的所有属性默认使用 byType 的依赖注入，若同一class有多个bean，则会报错。
//        definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
//
//        beanDefinitionRegistry.registerBeanDefinition(RedisTemplate.class.getName(), definition);

    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        log.info("{}", "postProcessBeanFactory");
    }

    // 获得上下文
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public void addBeanDefinitionInfo(String beanDefinitionName,BeanDefinition beanDefinition) {
        String type = beanDefinition.getClass().getSimpleName();
        BeanDefinitionInfo beanDefinitionInfo = new BeanDefinitionInfo();
        String beanClassName = beanDefinition.getBeanClassName();
        beanDefinitionInfo.setName(beanClassName);
        beanDefinitionInfo.setBeanName(beanDefinitionName);
        beanDefinitionInfo.setType(type);
        beanDefinitionInfo.setParentName(beanDefinition.getParentName());
        beanDefinitionInfo.setBeanClassName(beanClassName);

//            if (StringUtils.isBlank(beanClassName)) {
//                int i = 0;
//            }

        beanDefinitionInfo.setScope(beanDefinition.getScope());
        beanDefinitionInfo.setFactoryBeanName(beanDefinition.getFactoryBeanName());
        beanDefinitionInfo.setFactoryMethodName(beanDefinition.getFactoryMethodName());
        beanDefinitionInfo.setInitMethodName(beanDefinition.getInitMethodName());
        beanDefinitionInfo.setDestroyMethodName(beanDefinition.getDestroyMethodName());
        beanDefinitionInfo.setRole(beanDefinition.getRole());
        beanDefinitionInfo.setDescription(beanDefinition.getDescription());
        beanDefinitionInfo.setResourceDescription(beanDefinition.getResourceDescription());
        if (beanDefinition instanceof AbstractBeanDefinition) {
            AbstractBeanDefinition abstractBeanDefinition = (AbstractBeanDefinition) beanDefinition;
            beanDefinitionInfo.setAutowireMode(abstractBeanDefinition.getAutowireMode());
            beanDefinitionInfo.setDependencyCheck(abstractBeanDefinition.getDependencyCheck());
            beanDefinitionInfo.setIsLazyInit(abstractBeanDefinition.getLazyInit());
            beanDefinitionInfo.setIsAutowireCandidate(abstractBeanDefinition.isAutowireCandidate());
            beanDefinitionInfo.setIsPrimary(abstractBeanDefinition.isPrimary());
            beanDefinitionInfo.setIsSingleton(abstractBeanDefinition.isSingleton());
            beanDefinitionInfo.setIsPrototype(abstractBeanDefinition.isPrototype());
            beanDefinitionInfo.setIsAbstract(abstractBeanDefinition.isAbstract());
        }

        ResolvableType resolvableType = beanDefinition.getResolvableType();
        if (resolvableType.hasGenerics()) {
//                ResolvableType[] generics = resolvableType.getGenerics();
            String name = resolvableType.toString();
            beanDefinitionInfo.setName(name);
        }
//            log.info("{}",beanDefinition.getResolvableType());
//            log.info(JsonUtil.prettyFormat(beanDefinitionInfo));
        beanDefinitionInfoList.add(beanDefinitionInfo);
    }
}


